﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using GameSchool.Models;
using GameSchool.Models.Repositories;
using GameSchool.Models.ViewModels;


namespace GameSchool.Controllers
{
    public class CourseController : Controller
    {
        public ActionResult Index(int? ID)
        {
            //Retrive 10 most recent news in course from DB
            NewsRepository rep = new NewsRepository();
           var repList = rep.GetNewsByCourseID(ID).Take(10);
           var userID = (Guid)Membership.GetUser().ProviderUserKey;

           GameSchoolDBDataContext db = new GameSchoolDBDataContext();
           var isTeacher = (from u in db.IsInCourses
                            where u.UserID == userID && u.CourseID == ID
                            select u.IsTeacher).SingleOrDefault();

            if(User.IsInRole("Admin"))
                    isTeacher = true;

            //A list of the viewModel
            List<NewsItemViewModel> modelList = new List<NewsItemViewModel>();

            if (repList.Count() == 0)
            {

                NewsItemViewModel model = new NewsItemViewModel();
                //model.isTeacher = isTeacher;
                modelList.Add(model);

            }
            else
            {
                foreach (var n in repList)
                {
                    NewsItemViewModel model = new NewsItemViewModel();
                    model.date = n.DatePub;
                    model.parseCourseID(n.CourseID);
                    model.parseAuthorID(n.Author);
                    model.ID = n.ID;
                    model.Title = n.Title;
                    model.Body = n.Content;
                    //model.isTeacher = isTeacher;
                    modelList.Add(model);
                }
            }

            return View(modelList);
        }

 /*
        public ActionResult Createasdf()
        {
            LevelRepository rep = new LevelRepository();
            Level newLevel = new Level();
            var levels = rep.GetLevelsByCourseID(1);
            int count = levels.Count();

            newLevel.LevelNr = count + 1;
            newLevel.Date_start = DateTime.Now;
            newLevel.Date_finish = DateTime.Now;
            newLevel.CourseID = 1;
            rep.AddLevel(newLevel);
            rep.Save();
            return RedirectToAction("Index", "Home");
        }
        */

        //Harðkóðað, þarf js thingy til að vita hvaða course notandi er staddur í :D
        public ActionResult ListUsers(int? ID)
        {
            CourseRepository rep = new CourseRepository();
            var usersInCourse = rep.GetUsersByCourse(ID);//setja inn id hér þegar js er komið

            return View(usersInCourse);
        }
        
        public ActionResult AddUserToCourse()
        {
            var db = new GameSchoolDBDataContext();
            //Generates a dropdown list of courses with their id's as values and the choice as it's name
            IEnumerable<SelectListItem> items = db.Courses
              .Select(c => new SelectListItem
              {
                  Value = c.ID.ToString(),
                  Text = c.Name
              });
            ViewBag.CourseID = items;

            //Generates a dropdown list of users with their id's as values and the choice as their name
            IEnumerable<SelectListItem> users = db.UserProfiles
              .Select(u => new SelectListItem
              {
                  Value = u.UserID.ToString(),
                  Text = u.Name
              });
            ViewBag.UserID = users;
            return View();
        }

        [HttpPost]
        public ActionResult AddUserToCourse(IsInCourse putUserIntoCourse)
        {
            CourseRepository crs = new CourseRepository();
            crs.AddUserToCourse(putUserIntoCourse);
            crs.Save();

            return RedirectToAction("Index", "Home");
        }

        public ActionResult level(int? ID)
        {
            //Initializing the Repository's and lists used in this ActionResult
            var db = new GameSchoolDBDataContext();
            UserRepository urep = new UserRepository();
            CourseRepository crep = new CourseRepository();
            LevelRepository lrep = new LevelRepository();
            HandInRepository hrep = new HandInRepository();
            LectureRepository lerep = new LectureRepository();
            QuizRepository qrep = new QuizRepository();
            PointsRepository prep = new PointsRepository();
            List<LevelViewModel> list = new List<LevelViewModel>();
            Guid guid = new Guid();
            //Geting the clients UserID from the login
            guid = (Guid)Membership.GetUser().ProviderUserKey;
            //Geting the nmber of levels for the course
            var levels = lrep.GetLevelsByCourseID(ID);
            // Initializing the count variable used to query the correct level.
            int i = 1;
            // Initializing the variable used to determin if the level is open to the client.
            bool open= true;
            // loops once for each level in the course
            foreach (var d in levels)
            {
                // Initializing the instances of classes or lists that are required in each run instance of the loop 
                UserProfile user = new UserProfile();
                LevelViewModel levelModel = new LevelViewModel();
                var userPosition = new PointsViewModel();
                levelModel.assignmentList = new List<AssignmentViewModel>();
                Level L = new Level();
                // Getting the currect levelid given the current course and levelnumber.
                L = crep.LevelID(ID, i);
                int levelID = L.ID;
                              
                // Initializing local variables used in this function
                int? currentpoints = 0;
                int? maxpoints = 0;
                bool coursecompleted = true;

                // geting the required information from repositorys to display points and possition for the Level
                
                var pointsForLevel = prep.GetTotalPointsForLevel(ID, L.ID);
                var pointsAndPosition = prep.GetHighScoresAndPositionFromCourse(guid, pointsForLevel);
                
                // goes threw the list of positions and find the current user.
                foreach (var p in pointsAndPosition)
                {
                    if (p.userID == guid)
                    {
                        userPosition = p;
                    }

                }
                // the information for the level is added to the viewmodel.
                levelModel.levelNumber = i;
                levelModel.LevelID = L.ID;
                levelModel.position = userPosition.position;
                // geting the assignments for this current level

                var ass = lrep.GetAssignmentsByLevel(L.ID); 
                // loops for each assignment in the level
                foreach (var v in ass)
                {
                    // initializes the classes needed in this loop
                    AssignmentViewModel model = new AssignmentViewModel();
                    var pvm = new PointsViewModel();

                    // Checks if the assignment is a handin.
                    if (v.AssignmentType == "HandIn")
                    {

                        HandIn nHandIn = new HandIn();
                        AssignmentScore aScore1 = new AssignmentScore();

                        //gets the Handin information and the points for the assignment
                        nHandIn = hrep.GetHandInByID(v.ResourceID);
                        aScore1 = prep.GetAssignmentPoints(v.ID, guid);
                        //information being put into the viewmodel
                        model.assignmentID = v.ID;
                        model.assignmentType = v.AssignmentType;
                        model.assignmentTitle = nHandIn.Title;
                        model.maxPoints = nHandIn.MaxPoints;
                        model.bonusPoints = 0;
                        model.resourceID = nHandIn.ID;
                        maxpoints = model.maxPoints + maxpoints;
                        // checks if the user has finished the assignment and if he has puts his points into the viewmodel 
                        if (aScore1 != null)
                        {
                            model.bonusPoints = aScore1.Bonuspoints;
                            model.assignmentPoints = aScore1.Points;
                            currentpoints = currentpoints + aScore1.Points;
                            model.completed = true;
                            
                        }
                        // if he hasn't finished the assignment this is put into the viewmodel
                        else
                        {
                            model.assignmentPoints = 0;
                            model.completed = false;
                            coursecompleted = false;
                        }




                    }
                    // Checks if the assignment is a quiz.
                    else if (v.AssignmentType == "Quiz")
                    {
                        Quiz nQuiz = new Quiz();
                        AssignmentScore aScore2 = new AssignmentScore();
                        //gets the quiz information and the points for the assignment
                        nQuiz = qrep.GetQuizByID(v.ResourceID);
                        aScore2 = prep.GetAssignmentPoints(v.ID, guid);
                        //information being put into the viewmodel
                        model.assignmentID = v.ID;
                        model.assignmentType = v.AssignmentType;
                        model.assignmentTitle = nQuiz.Name;
                        model.maxPoints = nQuiz.MaxPoints;
                        model.bonusPoints = 0;
                        model.assignmentID = nQuiz.ID;
                        model.resourceID = nQuiz.ID;
                        maxpoints = model.maxPoints + maxpoints;
                        // checks if the user has finished the assignment and if he has puts his points into the viewmodel
                        if (aScore2 != null)
                        {
                            model.bonusPoints = aScore2.Bonuspoints;
                            model.assignmentPoints = aScore2.Points;
                            model.completed = true;
                            currentpoints = currentpoints + aScore2.Points;
                        }
                        // if he hasn't finished the assignment this is put into the viewmodel
                        else
                        {
                            model.assignmentPoints = 0;
                            model.completed = false;
                            coursecompleted = false;
                           
                        }


                    }
                   // Checks if the assignment is a Lecture.
                    else if (v.AssignmentType == "Lecture")
                    {
                        Lecture nLecture = new Lecture();
                        AssignmentScore aScore3 = new AssignmentScore();
                        //gets the quiz information and the points for the assignment
                        aScore3 = prep.GetAssignmentPoints(v.ID, guid);
                        nLecture = lerep.GetLectureByID(v.ResourceID);

                        //information being put into the viewmodel
                        model.assignmentID = v.ID;
                        model.assignmentType = v.AssignmentType;
                        model.assignmentTitle = nLecture.Title;
                        model.maxPoints = nLecture.MaxPoints;
                        model.resourceID = nLecture.ID;
                        model.bonusPoints = 0;
                        maxpoints = model.maxPoints + maxpoints;
                        // checks if the user has finished the assignment and if he has puts his points into the viewmodel
                        if (aScore3 != null)
                        {
                            model.bonusPoints = aScore3.Bonuspoints;
                            model.assignmentPoints = aScore3.Points;
                            model.completed = true;
                            currentpoints = currentpoints + aScore3.Points;
                        }
                        // if he hasn't finished the assignment this is put into the viewmodel
                        else
                        {
                            model.assignmentPoints = 0;
                            model.completed = false;
                            coursecompleted = false;
                            
                        }

                    }

                    
                    // gets the score and position using an amazing code that took forever to code.
                    var scoreAndPosition = prep.GetHighScoresAndPositionFromAssignment(guid, v.ID);
                    // goes threw the result and picks the current user from the list.
                    foreach (var p in scoreAndPosition)
                    {
                        if (p.userID == guid)
                        {
                            pvm = p;
                            // Puts your current possition in the assignment into the viewmodel
                            model.position = pvm.position;
                           
                        }

                        
                    }
                    // adds the viewmodel to the list of viewmodels.
                    levelModel.assignmentList.Add(model);

                              

                }
                // checks if its the first level in the assignment and as such should be open by default.
                if (i == 1)
                {
                    levelModel.finished = true;
                }
                // if its not the first level it check if the level prior to it was finished and open contains the boolean value for weather the assignments were finished or not.
                else
                {
                    levelModel.finished = open;
                }
                

                // points information for the level that has been summed threwout the level is added to the model.
                levelModel.levelPoints = currentpoints;
                levelModel.levelMaxPoints = maxpoints;
                i++;
                list.Add(levelModel);
                //if the level was completed the courescompleted variable will contain true and thus the lest level will be open.
                open = coursecompleted;
            }

            // checks if the user is an admin
            var admin = (
                          from u in db.IsInCourses
                          where u.CourseID == Convert.ToInt32(ID) && u.UserID == (Guid)Membership.GetUser().ProviderUserKey
                          select u.IsTeacher).SingleOrDefault();


            if (admin == null)
                admin = false;

            if(list.Count() != 0)
                list[0].isTeacher = admin;
                list[0].courseID = ID;

                return View(list);
        }
       
        public ActionResult TopScores(int? ID)
        {
            // initializing what i need for this function
            PointsRepository pointsrepo = new PointsRepository();
            UserRepository urep = new UserRepository();
            UserProfile userpro = new UserProfile();
            CourseRepository crep = new CourseRepository();
            //List<IOrderedEnumerable<PointsViewModel>> list = new List<IOrderedEnumerable<PointsViewModel>>();
            Guid guid = new Guid();
            Course courseInfo = new Course();
            Course cinfo = crep.GetCourseByID(ID);
            userpro = urep.GetUserProfileByID(guid);
            // gets the current user id from the client.
            guid = (Guid)Membership.GetUser().ProviderUserKey;
            
            // gets everyones points from the course
            var pointsForCourse = pointsrepo.GetTotalPointsForCourse(ID);
            // goes threw the list  and finds you and puts a boolean true on that line
            foreach (var v in pointsForCourse)
            {
                
                if (v.userID == guid)
                {
                    v.ITSME = true;
                    v.name = userpro.Name;

                }
                else
                {
                    v.ITSME = false;
                    v.name = "-";
                }
            }
            ViewData["list"] = pointsForCourse;
            ViewData["courseName"] = cinfo.Name;
            return View();
        }

        public JsonResult GetCoursePoints(int? ID)
        {

            //Hook up to the DB and get the users ID.
            GameSchoolDBDataContext db = new GameSchoolDBDataContext();
            var userID = (Guid)Membership.GetUser().ProviderUserKey;

            //This is a model we'll be using to collect the information into.
            var CoursePointsModel = new CoursePointsModel();

            //Get a list of users, and the sum of their points for this course.. We also order the list by points.
            var userPointsList = from p in db.AssignmentScores
                                          from c in db.Courses
                                where c.ID == ID
                                 group p by p.UserID into g
                                 orderby g.Sum(p => p.Points) descending
                                 select new { uID = g.Key, Points = g.Sum(p => p.Points) };

            //We need to parse the Anonymous types returned above into a list of KeyValuePair so that we can use Select() and ElementAt() on the list.
            List<KeyValuePair<Guid?, int?>> toList = new List<KeyValuePair<Guid?, int?>>();
            foreach (var u in userPointsList)
            {
                toList.Add(new KeyValuePair<Guid?, int?>(u.uID, u.Points));
            }

            //Find out where in the list the current user is. So pretty ..
            int currentPosition = toList.Select((item, index) => new { index, item }) //Create a way to index each item..
                .Where(itemWithIndex => itemWithIndex.item.Key == userID)        //Find the current user in the list
                .FirstOrDefault().index;                                                                //And select him.

            #region Adding the points etc. into the model - cruddy code.
            //Getting points to be displayed and putting them into the model we created; above, current and below.           
            CoursePointsModel.abovePoints = toList.ElementAtOrDefault(currentPosition - 1).Value;
            CoursePointsModel.totalPoints = toList.ElementAtOrDefault(currentPosition).Value;
            CoursePointsModel.belowPoints = toList.ElementAtOrDefault(currentPosition + 1).Value;
            //Also adding the relative position of the user to the PointsModel so we can display what seat the user is in.
            CoursePointsModel.currentPosition = currentPosition + 1;
            #endregion

            //Now we just need the information for the current level. Since the function doesn't know what level we're currently on we have to plock that out first..
            #region LevelPlocking

            CoursePointsModel.currentLevel = 1;
            CoursePointsModel.levelMaxPoints = 100;
            CoursePointsModel.levelPoints = 20;

            //Should give us the highest level ID .. I think that'll work.
            var levelID = (from a in db.AssignmentScores
                           from ass in db.Assignments
                           where a.UserID == userID && a.AssignmentID == ass.ID
                           orderby ass.LevelID descending
                           select ass.LevelID).Take(1);

            //Getting the actual level position
            CoursePointsModel.currentLevel = (from l in db.Levels
                                                 where l.ID == levelID.First()
                                                 select l.LevelNr).SingleOrDefault();
            
            //These functions already exist - so if this is wrong when rendered it means that the functions are wrong.
            var pointsRepo = new PointsRepository();
            CoursePointsModel.levelPoints = pointsRepo.GetLevelPoints(levelID.First(), userID);
            CoursePointsModel.levelMaxPoints = pointsRepo.GetMaxLevelPoints(levelID.First(), userID);
            #endregion

            return Json(CoursePointsModel, JsonRequestBehavior.AllowGet);
        }
        
        
        //Might be cool to convert the level adding functionality to Json - if we get the time.
        [HttpGet]
        public ActionResult AddLevel(int? ID)
        {

            //Check if we actually got an integer as parameter.
            if(ID == null)
                    throw new ArgumentNullException("AddLevel - null passed as parameter");
            var userID = (Guid)Membership.GetUser().ProviderUserKey;

            //Need to check if the user is a teacher or admin
            if(! User.IsInRole("Admin"))
            {
                var db = new GameSchoolDBDataContext();
                var isTeacher = (from u in db.IsInCourses
                                         where u.UserID == userID && u.CourseID == ID
                                         select u.IsTeacher).SingleOrDefault();

                //If the user isn't a teacher nor admin we throw him back to his homepage.
                if(isTeacher != true)
                        return RedirectToAction("Index", "Home");

            }
            //If we got this far we got the Course ID, and the user is either admin or teaches the course.
            
            var lRep = new LevelRepository();
            var l = new Level();
            l.CourseID = ID;

            //Getting the currently highest level number for levels in the course and incrementing by 1.

            return View(l);

        }

        public ActionResult CreateCourse()
        {
            return View();
        }
        [HttpPost]
        public ActionResult CreateCourse(Course newCourse)
        {
            LevelRepository lrep = new LevelRepository();
            CourseRepository rep = new CourseRepository();
            Level L = new Level();
            rep.AddCourse(newCourse);
            
            rep.Save();

            //When we create a new course we also have to add a new level to that course.
            LevelRepository levelRep = new LevelRepository();
            Level l = new Level();

            GameSchoolDBDataContext db = new GameSchoolDBDataContext();
            l.CourseID = (from c in db.Courses
                          where c.Name == newCourse.Name
                          select c.ID).SingleOrDefault();

            l.LevelNr = 1;
            levelRep.AddLevel(l);
            levelRep.Save();

            return RedirectToAction("Index", "Home");
        }

        

        [HttpPost]
        public ActionResult AddLevel(Level l)
        {
            //We might want to errorcheck this.
            var rep = new LevelRepository();

            //Find out the highest levelNumber in this course.
            int? highestLevel = l.LevelNr = rep.GetLevelsByCourseID(l.CourseID).Count();

            //If there are no levels we set the levelNumber to 1 - but if not we increment the levelNumber by one.
            //This makes sure that the course won't get two levels with the same levelNumber.
                l.LevelNr = Convert.ToInt32(highestLevel + 1);

            //Save the level.
            rep.AddLevel(l);
            rep.Save();

            //Redirect the user back to the course page.
            return RedirectToAction("Level/"  + l.CourseID, "Course");

        }


  /*      public ActionResult JustLevelScore()
        {
            PointsRepository prep = new PointsRepository();
            UserRepository urep = new UserRepository();
            Guid guid = new Guid();
            UserProfile user = new UserProfile();

            guid = (Guid)Membership.GetUser().ProviderUserKey;
            user = urep.GetUserProfileByID(guid);
            var ble = prep.GetTotalPointsForLevel(1,1);
            var ble2 = prep.GetHighScoresAndPositionFromCourse(guid, ble);
            var blessabubu = new PointsViewModel();
            foreach (var p in ble2)
            {
                if (p.userID == guid)
                {
                    blessabubu = p;
                }

            }

            return View(blessabubu);
            
        }
   */

    /*   public ActionResult JustCourseScore()
        {
            PointsRepository prep = new PointsRepository();
            UserRepository urep = new UserRepository();
            Guid guid = new Guid();
            UserProfile user = new UserProfile();

            guid = (Guid)Membership.GetUser().ProviderUserKey;
            user = urep.GetUserProfileByID(guid);
            var ble = prep.GetTotalPointsForCourse(1);
            var ble2 = prep.GetHighScoresAndPositionFromCourse(guid, ble);
            var blessabubu = new PointsViewModel();
            foreach (var p in ble2)
            {
                if (p.userID == guid)
                {
                    blessabubu = p;
                }

            }

            return View(blessabubu);

        }
     */


  }
        //
        // GET: /Course/

    /*
        [HttpGet]
        public ActionResult EditCourse(int? id)
        {
            return View();
        }
        [HttpPost]
        public ActionResult EditCourse(CourseEditViewModel itemVM)
        {
            return View();
        }
        public ActionResult DeleteCourse()
        {
            return View();
        }
        [HttpGet]
        public ActionResult CreateLevel()
        {
            LevelEditViewModel item = new LevelEditViewModel();
            return View(item);
        }
        [HttpPost]
        public ActionResult CreateLevel(LevelEditViewModel itemVM)
        {
            return View();
        }
       
        public ActionResult GetLevel()
        {
            return View();
        }
        [HttpGet]
        public ActionResult EditLevel(int? id)
        {
            return View();
        }
        [HttpPost]
        public ActionResult EditLevel(LevelEditViewModel itemVM)
        {
            return View();
        }
        public ActionResult DeleteLevel()
        {
            return View();
        }
      */

}

